from Token import Token
from TokenType import TokenType, is_token
from decimal import Decimal


class Lexer:
    __expression: str = None
    __pos: int = None
    __current_char = None

    def __init__(self, expression: str):
        self.__expression = expression
        self.__pos = 0
        self.__current_char = self.__expression[self.__pos]

    def error(self):
        raise Exception('Invalid character')

    def advance(self):
        self.__pos += 1
        if self.__pos > len(self.__expression) - 1:
            self.__current_char = None
        else:
            self.__current_char = self.__expression[self.__pos]

    def skip_whitespace(self):
        while self.__current_char is not None and self.__current_char.isspace():
            self.advance()

    def get_number(self) -> Decimal:
        result = ''
        while self.__current_char is not None and self.__current_char.isdigit() or self.__current_char == '.':
            result += self.__current_char
            self.advance()
        return Decimal(result)

    def get_variable(self) -> str:
        result = ''
        escape = False
        while self.__current_char is not None:
            if self.__current_char == '\\':
                escape = True
            elif escape:
                escape = False
                result += self.__current_char
            elif is_token(self.__current_char):
                result += self.__current_char
            else:
                break
            self.advance()
        return result

    def get_next_token(self):
        while self.__current_char is not None:
            if self.__current_char.isspace():
                self.skip_whitespace()
                continue

            if self.__current_char.isdigit():
                return Token(TokenType.NUMBER, self.get_number())

            if self.__current_char == '+':
                self.advance()
                return Token(TokenType.PLUS, '+')

            if self.__current_char == '-':
                self.advance()
                return Token(TokenType.MINUS, '-')

            if self.__current_char == '*':
                self.advance()
                return Token(TokenType.MULTIPLY, '*')

            if self.__current_char == '/':
                self.advance()
                return Token(TokenType.DIVIDE, '/')

            if self.__current_char == '(':
                self.advance()
                return Token(TokenType.LEFT_BRACKET, '{')

            if self.__current_char == ')':
                self.advance()
                return Token(TokenType.RIGHT_BRACKET, ')')

            if self.__current_char == '^':
                self.advance()
                return Token(TokenType.POWER, '^')

            variable = self.get_variable()
            if variable != '':
                token = Token(TokenType.VARIABLE, variable)
                return token
            self.error()

        return Token(TokenType.EOF, None)
